package com.atguigu.gmall.seckill.service.impl;

import com.atguigu.gmall.common.constans.RedisConstant;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.AuthUtil;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.common.util.JsonUtil;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.model.to.SecKillQueueTo;
import com.atguigu.gmall.serviceutil.annotation.AppCache;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.atguigu.gmall.seckill.service.SeckillGoodsService;
import com.atguigu.gmall.seckill.mapper.SeckillGoodsMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 *
 */
@Service
public class SeckillGoodsServiceImpl extends ServiceImpl<SeckillGoodsMapper, SeckillGoods>
    implements SeckillGoodsService{
    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    //实现秒杀商品列表查询
    //@AppCache(cacheKey = RedisConstant.SECKILL_GOODS_LIST_PREFIX+"#{#currentDate}")
    @Override
    public List<SeckillGoods> seckillListCurrDate()  {
        List<SeckillGoods> seckillList = null;
        //获取当前日期
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String format = simpleDateFormat.format(new Date());
        String cacheKey = RedisConstant.SECKILL_GOODS_LIST_PREFIX+format;
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(cacheKey);
        redisTemplate.expire(cacheKey, 2, TimeUnit.DAYS); //缓存有效期2天
        //判断缓存是否存在
        Boolean exist = operations.hasKey(cacheKey); //true表示缓存不存在，false表示缓存存在
        if (exist){
            //缓存存在，直接返回缓存
            seckillList = operations.values().stream()
                    .map(json -> {
                        return JsonUtil.jsonToObject(json, new TypeReference<SeckillGoods>() {
                        });
                    }).collect(Collectors.toList());
            return seckillList;
        }else {
            //缓存不存在，查询数据库并缓存,先加锁
            RLock lock = redissonClient.getLock(RedisConstant.LOCK_PREFIX + cacheKey);
            boolean tryLock = lock.tryLock(); //尝试获取锁
            if (tryLock){
                //加锁成功，查询数据库并缓存
                seckillList = seckillGoodsMapper.getSeckillList(format);
                seckillList.forEach(seckillGoods -> {
                    operations.put(seckillGoods.getSkuId().toString(), JsonUtil.toStr(seckillGoods));
                });
                if (lock.isLocked()){
                    lock.unlock(); //释放锁
                }
            }else {
                //加锁失败，等待查询缓存
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                //缓存存在，直接返回缓存
                seckillList = operations.values().stream()
                        .map(json -> {
                            return JsonUtil.jsonToObject(json, new TypeReference<SeckillGoods>() {
                            });
                        }).collect(Collectors.toList());
                return seckillList;
            }

            return seckillList;
        }



    }

    @Override
    public List<SeckillGoods> seckillListDescDate(String date) {
        return seckillGoodsMapper.getSeckillList(date);
    }

    @Override
    public SeckillGoods seckillDetail(Long skuId) {
        //获取当前日期
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String format = simpleDateFormat.format(new Date());
        String cacheKey = RedisConstant.SECKILL_GOODS_LIST_PREFIX+format;
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps(cacheKey);
        String json = operations.get(skuId.toString());
        SeckillGoods seckillGoods = JsonUtil.jsonToObject(json, new TypeReference<SeckillGoods>() {
        });
        return seckillGoods;
    }
    //减库存并保存订单
    @Override
    public void reduceStock(SecKillQueueTo secKillQueueTo) {
        seckillGoodsMapper.reduceStockOne(secKillQueueTo.getSkuId());
    }
    //查询订单详情
    @Override
    public OrderInfo orderDetails(Long skuId) {
        Long userId = AuthUtil.getAuthTo().getUserId();
        String dateStr = DateUtil.formatDate(new Date());
        //seckill:order:17:2025-09-19:46
        String key =RedisConstant.SECKILL_ORDER_PREFIX + userId + ":" + dateStr + ":" + skuId;
        String orderInfoJson=redisTemplate.opsForValue().get(key);
        if (orderInfoJson ==null){
            throw  new GmallException(ResultCodeEnum.SECKILL_FINISH);
        }
        OrderInfo orderInfo = JsonUtil.jsonToObject(orderInfoJson, new TypeReference<OrderInfo>() {
        });

        return orderInfo;
    }
}




